package com.ccsoft.netty.simple;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * Netty 通信服务端
 */
public class NettyServer {
    public static void main(String[] args) throws InterruptedException {
        // 创建两个事件循环组，bossGroup 负责处理 accept 请求
        // workerGroup 负责执行具体的业务
        // 创建下面group对象时没有显式指定线程数量，则 Netty 默认创建 cpu 核心数量 * 2 个线程
        // 如果是1CPU2核，那么 bossGroup 创建4个线程，workerGroup也是4个线程
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // 创建服务端启动对象，配置服务端参数
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)// 绑定两个线程组
                    .channel(NioServerSocketChannel.class)//实现服务器通道的类
                    .option(ChannelOption.SO_BACKLOG, 128)//线程队列的最大连接数
                    .childOption(ChannelOption.SO_KEEPALIVE, true)//保持活动链接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() {// 创建通道初始化对象
                        //给 pipeline 设置处理器
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            /** 这里保存 socketChannel （每个客户端一个 socketChannel），之后可调用指定的 socketChannel 实现推送消息的功能*/
                            socketChannel.pipeline().addLast(new NettyServerHandler());// 为 workerGroup 的 EventLoop 对应的管道设置处理器
                        }
                    });
            ChannelFuture channelFuture = serverBootstrap.bind(6668).sync();// 服务端绑定端口并启动
//            System.out.println("...服务端准备完毕...");// 监听 closeFuture 之后的代码执行不到，这里是可见的最后一行
            channelFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture) throws Exception {
                    if(channelFuture.isSuccess()) System.out.println("服务端绑定端口6668成功");
                    else System.out.println("服务端绑定端口6668失败~~~");
                }
            });
            channelFuture.channel().closeFuture().sync();// 监听关闭通道的事件 - 通道被关闭则会触发
        } finally {
            // 通信过程中出现异常则优雅的关闭两个 group
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
